package com.carbeauty.common.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 全局异常处理器
 * 
 * 统一处理系统中的各种异常:
 * - 业务异常处理
 * - 数据验证异常处理
 * - 系统异常处理
 * - 404/500等HTTP状态异常
 * 
 * 异常处理策略:
 * - AJAX请求返回JSON格式错误信息
 * - 页面请求跳转到错误页面
 * - 记录异常日志便于排查问题
 * 
 * @author CarBeauty Team
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    // ==================== 业务异常处理 ====================
    
    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public Object handleBusinessException(BusinessException e, HttpServletRequest request) {
        logger.warn("业务异常: {}", e.getMessage());
        
        if (isAjaxRequest(request)) {
            // AJAX请求返回JSON
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", e.getMessage());
            result.put("code", e.getCode());
            return ResponseEntity.badRequest().body(result);
        } else {
            // 页面请求跳转到错误页面
            ModelAndView mv = new ModelAndView("error/business");
            mv.addObject("message", e.getMessage());
            mv.addObject("code", e.getCode());
            return mv;
        }
    }
    
    /**
     * 处理资源不存在异常
     */
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Object handleResourceNotFoundException(ResourceNotFoundException e, HttpServletRequest request) {
        logger.warn("资源不存在: {}", e.getMessage());
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", e.getMessage());
            result.put("code", "RESOURCE_NOT_FOUND");
            return ResponseEntity.notFound().build();
        } else {
            ModelAndView mv = new ModelAndView("error/404");
            mv.addObject("message", e.getMessage());
            return mv;
        }
    }
    
    // ==================== 数据验证异常处理 ====================
    
    /**
     * 处理方法参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        logger.warn("参数验证失败: {}", e.getMessage());
        
        Map<String, String> errors = new HashMap<>();
        e.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "参数验证失败");
            result.put("errors", errors);
            return ResponseEntity.badRequest().body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/validation");
            mv.addObject("message", "参数验证失败");
            mv.addObject("errors", errors);
            return mv;
        }
    }
    
    /**
     * 处理绑定异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object handleBindException(BindException e, HttpServletRequest request) {
        logger.warn("数据绑定失败: {}", e.getMessage());
        
        Map<String, String> errors = new HashMap<>();
        e.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "数据绑定失败");
            result.put("errors", errors);
            return ResponseEntity.badRequest().body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/validation");
            mv.addObject("message", "数据绑定失败");
            mv.addObject("errors", errors);
            return mv;
        }
    }
    
    /**
     * 处理约束违反异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        logger.warn("约束验证失败: {}", e.getMessage());
        
        Map<String, String> errors = new HashMap<>();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            String fieldName = violation.getPropertyPath().toString();
            String errorMessage = violation.getMessage();
            errors.put(fieldName, errorMessage);
        }
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "约束验证失败");
            result.put("errors", errors);
            return ResponseEntity.badRequest().body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/validation");
            mv.addObject("message", "约束验证失败");
            mv.addObject("errors", errors);
            return mv;
        }
    }
    
    // ==================== 系统异常处理 ====================
    
    /**
     * 处理空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object handleNullPointerException(NullPointerException e, HttpServletRequest request) {
        logger.error("空指针异常", e);
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "系统内部错误");
            result.put("code", "NULL_POINTER");
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/500");
            mv.addObject("message", "系统内部错误");
            return mv;
        }
    }
    
    /**
     * 处理非法参数异常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
        logger.warn("非法参数异常: {}", e.getMessage());
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", e.getMessage());
            result.put("code", "ILLEGAL_ARGUMENT");
            return ResponseEntity.badRequest().body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/400");
            mv.addObject("message", e.getMessage());
            return mv;
        }
    }
    
    /**
     * 处理运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        logger.error("运行时异常", e);
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "系统运行异常: " + e.getMessage());
            result.put("code", "RUNTIME_ERROR");
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/500");
            mv.addObject("message", "系统运行异常: " + e.getMessage());
            return mv;
        }
    }
    
    /**
     * 处理所有其他异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object handleException(Exception e, HttpServletRequest request) {
        logger.error("未知异常", e);
        
        if (isAjaxRequest(request)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "系统异常，请联系管理员");
            result.put("code", "UNKNOWN_ERROR");
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
        } else {
            ModelAndView mv = new ModelAndView("error/500");
            mv.addObject("message", "系统异常，请联系管理员");
            return mv;
        }
    }
    
    // ==================== 辅助方法 ====================
    
    /**
     * 判断是否为AJAX请求
     */
    private boolean isAjaxRequest(HttpServletRequest request) {
        String requestedWith = request.getHeader("X-Requested-With");
        String accept = request.getHeader("Accept");
        String contentType = request.getContentType();
        
        return "XMLHttpRequest".equals(requestedWith) ||
               (accept != null && accept.contains("application/json")) ||
               (contentType != null && contentType.contains("application/json"));
    }
}
